home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Multimedia & Desktop / sk8 / SK8InJava / Code / Collections / TextCollection.java < prev    next >
Encoding:
Java Source  |  1997-02-27  |  7.1 KB  |  211 lines  |  [TEXT/CWIE]

  1. /*  SK8 © 1997 Apple Computer, Inc.
  2.     This code is protected under the current SK8 License
  3.     See http://sk8.research.apple.com/ for more information
  4.     Apple Research Laboratories
  5. */
  6.  
  7.  
  8. /********************************************************************
  9.  *
  10.  * text, part of the SK8 collection protocol
  11.  *
  12.  * text would be just a wrapper around the java class StringBuffer,
  13.  * but it's not since StringBuffer does not support removing of characters, 
  14.  * which the SK8 collection protocol requires.
  15.  * 
  16.  * Here's how text deals with removing characters: a text
  17.  * keeps track of the index of characters that have been removed, and then 
  18.  * skips over these characters when the caller requests an opperation on chars
  19.  * at a particular index (from the wrapped StringBuffer). 
  20.  * From time to time, the StringBuffer is recreated without
  21.  * the dead characters.
  22.  * 
  23.  **********************************************************************/
  24.  
  25. public abstract class text extends collection {
  26.     // private data members
  27.     private StringBuffer mStringBuffer;
  28.     private final int cMaxDeadCharRuns = 40;
  29.     private final int cDeadCharIndex = 0;         //for array access
  30.     private final int cDeadCharRunLength = 1;    //for array access
  31.     private final int cNullIndex = -1; 
  32.     
  33.     private int[][]      mDeadChars;
  34.     
  35.     
  36.     /**
  37.      ** Constructors
  38.      **/
  39.     public text(StringBuffer inString){
  40.          mStringBuffer = inString;
  41.          mDeadChars = new int[cMaxDeadCharRuns][2];
  42.          for (int i = 0; i < cMaxDeadCharRuns; i++)
  43.              mDeadChars[i][cDeadCharIndex] = cNullIndex;
  44.     }
  45.      
  46.     public text(String inString){
  47.          mStringBuffer = new StringBuffer(inString);
  48.          mDeadChars = new int[cMaxDeadCharRuns][2];
  49.          for (int i = 0; i < cMaxDeadCharRuns; i++)
  50.              mDeadChars[i][cDeadCharIndex] = cNullIndex;;
  51.     }
  52.              
  53.     public String toString(){
  54.         refreshBuffer();
  55.         return new String(mStringBuffer);
  56.     }
  57.     
  58.     protected int stringLength() {
  59.         if (mStringBuffer == null)
  60.             throw new RuntimeException("text not properly initialized");
  61.             
  62.         int len = mStringBuffer.length();
  63.         for(int i = 0; (i < cMaxDeadCharRuns) && (mDeadChars[i][cDeadCharIndex] != cNullIndex); i++){
  64.              len -= mDeadChars[i][cDeadCharRunLength];
  65.          }
  66.         return len;
  67.     }
  68.     
  69.     protected char getNthChar(int inIndex) {
  70.         if (mStringBuffer == null)
  71.             throw new RuntimeException("text not properly initialized");
  72.         return mStringBuffer.charAt(ApparentIndexToActual(inIndex));
  73.     }
  74.      
  75.     protected void setNthChar(int inIndex, char inCh)  {
  76.         if (mStringBuffer == null)
  77.             throw new RuntimeException("text not properly initialized");
  78.         mStringBuffer.setCharAt(ApparentIndexToActual(inIndex), inCh);
  79.     }
  80.             
  81.     protected void insertCharacter(int inIndex, char inCh)  {
  82.         if (mStringBuffer == null)
  83.             throw new RuntimeException("text not properly initialized");
  84.             
  85.         int i = ApparentIndexToActual(inIndex);
  86.         mStringBuffer.insert(i, 1);
  87.         mStringBuffer.setCharAt(i, inCh);    
  88.     }
  89.     
  90.     protected void getChars(int inStart, int inEnd, char[] inDest, int inDestBegin) {
  91.         if (mStringBuffer == null)
  92.             throw new RuntimeException("text not properly initialized");
  93.             
  94.         refreshBuffer();
  95.         mStringBuffer.getChars(inStart, inEnd, inDest, inDestBegin);
  96.     }
  97.  
  98.     
  99.     protected void insertString(int inIndex, String inStr) {
  100.         if (mStringBuffer == null)
  101.             throw new RuntimeException("text not properly initialized");
  102.             
  103.         refreshBuffer();
  104.         mStringBuffer.insert(inIndex, inStr);
  105.     }
  106.     
  107.     protected void removeChars(int inStart, int inEnd)  {
  108.         // if the list of deadChars is full, then refresh everything
  109.         if (mDeadChars[cMaxDeadCharRuns - 1][cDeadCharIndex] != cNullIndex)
  110.             refreshBuffer();
  111.             
  112.         int actualIndex = ApparentIndexToActual(inStart);
  113.         int numDying = inEnd - inStart;
  114.         
  115.         // find block before which the new block will go
  116.         int blockAfter = 0;
  117.         for (blockAfter = 0; blockAfter < cMaxDeadCharRuns; blockAfter++){
  118.             if((mDeadChars[blockAfter][cDeadCharIndex] == cNullIndex) ||
  119.                 (mDeadChars[blockAfter][cDeadCharIndex] > actualIndex)){
  120.                     break;
  121.             }
  122.         }
  123.         
  124.         if ((mDeadChars[blockAfter][cDeadCharIndex] != cNullIndex) &&
  125.             (mDeadChars[blockAfter][cDeadCharIndex] > actualIndex) &&
  126.             (numDying + actualIndex >= mDeadChars[blockAfter][cDeadCharIndex])){
  127.             //adjust the next block, instead of adding a new one
  128.                 int oldIndex = mDeadChars[blockAfter][cDeadCharIndex];
  129.                 mDeadChars[blockAfter][cDeadCharIndex] = actualIndex;
  130.                 mDeadChars[blockAfter][cDeadCharRunLength] += (oldIndex - actualIndex);
  131.                 int numStillToDie = numDying - (oldIndex - actualIndex);
  132.                 if (numStillToDie > 0)
  133.                     removeChars(inStart, inStart + numStillToDie);
  134.         } else { 
  135.             //dont havt to deal with next block
  136.             for (int i = cMaxDeadCharRuns - 2; i > blockAfter; i--){
  137.                 if (mDeadChars[i][cDeadCharIndex] != cNullIndex){
  138.                     mDeadChars[i + 1][cDeadCharIndex] = mDeadChars[i][cDeadCharIndex];
  139.                     mDeadChars[i + 1][cDeadCharRunLength] = mDeadChars[i][cDeadCharRunLength];
  140.                 }
  141.             }
  142.             // now blockAfter is our new target
  143.             mDeadChars[blockAfter][cDeadCharIndex] = actualIndex;
  144.             mDeadChars[blockAfter][cDeadCharRunLength] = numDying;
  145.         }
  146.     }
  147.     
  148.     /* 
  149.      * private stuff, dealing with dead characters
  150.      */
  151.      
  152.      private void refreshBuffer(){
  153.          if (mDeadChars[0][cDeadCharIndex] != cNullIndex) { //only do the work if we have to 
  154.  
  155.              StringBuffer newbie = new StringBuffer();
  156.              int endOfLastRun = 0;
  157.              
  158.              int tempBufferSize= 0;
  159.              int endOfOKRun;
  160.              int beginOfOKRun = 0; 
  161.              for(int i = 0; (i < cMaxDeadCharRuns); i++){
  162.                  if (mDeadChars[i][cDeadCharIndex] == cNullIndex){
  163.                      endOfOKRun = mStringBuffer.length();
  164.                  } else {
  165.                      endOfOKRun = mDeadChars[i][cDeadCharIndex];
  166.                  }
  167.                 if (tempBufferSize < (endOfOKRun - beginOfOKRun))
  168.                     tempBufferSize = endOfOKRun - beginOfOKRun;
  169.                     
  170.                 //set up for next time through this loop
  171.                 if (mDeadChars[i][cDeadCharIndex] != cNullIndex)
  172.                     beginOfOKRun = mDeadChars[i][cDeadCharIndex] + mDeadChars[i][cDeadCharRunLength];
  173.                 else
  174.                     break;
  175.             }
  176.             char[] tempBuffer = new char[tempBufferSize];
  177.              
  178.  
  179.              for(int i = 0; (i < cMaxDeadCharRuns) && (mDeadChars[i][cDeadCharIndex] != cNullIndex); i++){
  180.                  mStringBuffer.getChars(endOfLastRun, mDeadChars[i][cDeadCharIndex], tempBuffer, 0);
  181.                  newbie.append(tempBuffer, 0, (mDeadChars[i][cDeadCharIndex] - endOfLastRun));
  182.                  endOfLastRun = mDeadChars[i][cDeadCharIndex] + mDeadChars[i][cDeadCharRunLength];
  183.                  //clean out the list
  184.                  mDeadChars[i][cDeadCharIndex] = cNullIndex;
  185.              }
  186.              //now, the last bit...
  187.              if (endOfLastRun < mStringBuffer.length()){
  188.                  mStringBuffer.getChars(endOfLastRun, mStringBuffer.length(), tempBuffer, 0);
  189.                  newbie.append(tempBuffer,  0, (mStringBuffer.length() - endOfLastRun));
  190.              }
  191.              mStringBuffer = newbie;
  192.          }
  193.      }
  194.      
  195.      private int ApparentIndexToActual(int inApparent) {
  196.          // in which we count the dead chars before the char we care about
  197.          if (mStringBuffer == null)
  198.             throw new RuntimeException("text not properly initialized");
  199.         
  200.         int deadChars = 0;
  201.         int OKChars   = 0;
  202.         for (int i = 0;  ((i < cMaxDeadCharRuns) && 
  203.                         (mDeadChars[i][cDeadCharIndex] != cNullIndex)) ; i++) {
  204.             OKChars = (mDeadChars[i][cDeadCharIndex] - deadChars);
  205.             if (OKChars > inApparent) //it's > not >= cuz both indices start at zero
  206.                 break;
  207.             deadChars += mDeadChars[i][cDeadCharRunLength];
  208.         }
  209.         return inApparent + deadChars;
  210.     }
  211. }